package game
import (
	"math/rand"
	"config"
	"message"
	"github.com/name5566/leaf/log"
	"time"
	"strconv"
	"github.com/golang/protobuf/proto"
)

type Hall struct {
	hallID  int           // 大厅id
	rooms   map[int]*Room // 存放所有房间信息
	players map[int]*User // 进入该大厅的所有玩家
}

func (self *Hall) str() string {
	return strconv.Itoa(self.hallID)
}

func (self *Hall) onInit() {
	self.rooms = make(map[int]*Room)
	self.players = make(map[int]*User)
	self.createRooms()
}

// 销毁时调用
func (self *Hall) onDestroy() {
	removeHall(self.hallID)
}

// 返回room列表
func (self *Hall) getRoomList() []*Room {
	var list []*Room
	for _, v := range self.rooms {
		list = append(list, v)
	}
	return list
}

// 根据配置创建出所有的大厅
func (self *Hall) createRooms() {
	cfg := config.GetHallConfig(self.hallID)
	if cfg == nil {
		log.Error("无法获取大厅配置:  %v", self.hallID)
		return
	}
	roomCount := cfg.RoomCount
	for i := 0; i < roomCount; i++ {
		room := &Room{
			hallID:self.hallID,
			roomID:self.hallID * 1000 + i,
		}
		self.rooms[room.roomID] = room
		room.onInit()
	}
}

// 获取大厅数据（用于传递给客户端）
func (self *Hall) getHallInfo() *message.HallInfo {
	cfg := config.GetHallConfig(self.hallID)
	return &message.HallInfo{
		HallID:proto.Int(self.hallID),
		PlayerCount:proto.Int(len(self.players)),
		HallName:proto.String(cfg.HallName),
		SmallBlind:proto.Int(cfg.SmallBlind),
		BigBlind:proto.Int(cfg.BigBlind),
		MinMoney:proto.Int(cfg.MinMoney),
		MaxMoney:proto.Int(cfg.MaxMoney),
		LimitBet:proto.Int(cfg.LimitBet),
		MaxCount:proto.Int(cfg.MaxCount),
	}
}

// 玩家进入大厅
func (self *Hall) onPlayerEnterHall(player *User, autoEnterRoom bool) {
	log.Debug("onPlayerEnterHall: %v", player.str())

	/*TODO 判定玩家条件，如携带金额
	# 应该在这里做一些条件，允许进入后返回给角色进入成功

	# 如果需要记录该大厅上的人也可以在此做记录
	*/
	self.players[player.ID()] = player
	player.hallID = self.hallID

	if autoEnterRoom {
		room := self.getValidRoom()
		if room != nil {
			log.Debug("进入房间:  %v  %v", player.str(), room.roomID)
			player.totalMoneyBegin = player.data.TotalMoney
			room.onPlayerEnterRoom(player, true, true)
		} else {
			log.Error("找不到合适的房间:  %v", player.str())
		}

	}
}

// 玩家离开大厅
func (self *Hall) onPlayerLeaveHall(player *User) {
	log.Debug("onPlayerLeaveHall: %v", player.str())
	// 应该在这里做一些条件，允许进入后返回给角色离开成功
	if _, ok := self.players[player.ID()]; ok {
		delete(self.players, player.ID())
	}
}

// 玩家切换房间（在本大厅内随机取另外一个房间）
func (self *Hall) onPlayerChangeRoom(player *User, roomID int) {
	log.Debug("onPlayerChangeRoom: %v", player.str())

	// 离开原房间
	curRoom := self.getRoom(roomID)
	if curRoom != nil {
		curRoom.onPlayerLeaveRoom(player)
	}

	// 通知玩家自身，处理切换房间的表现(如房间变模糊)
	player.SendMsg(message.MSG_CHANGE_ROOM, nil)

	// 加入新房间(随机打乱顺序取一个)
	tempRooms := RandShuffleRoom(self.getRoomList())
	var newRoom *Room
	for _, room := range tempRooms {
		if room.roomID != roomID && room.couldEnter() {
			log.Debug("切换房间:  %v", room.str())
			newRoom = room
			break
		}
	}

	if newRoom != nil {
		newRoom.onPlayerEnterRoom(player, true, true)
	} else {
		// 无法找到新的房间，则退回到大厅
		log.Error("无法找到新的房间")
		player.reqStopGame()
	}
}

// 随机排序房间列表
func RandShuffleRoom(src []*Room) []*Room {
	dest := make([]*Room, len(src))
	rand.Seed(time.Now().UTC().UnixNano())
	perm := rand.Perm(len(src))
	for i, v := range perm {
		dest[v] = src[i]
	}
	return dest
}


// 获取一个空的房间，将来修改为考虑负载均衡的情况
func (self *Hall) getValidRoom() *Room {
	for _, v := range self.rooms {
		if v.couldEnter() {
			return v
		}
	}
	return nil
}

// 获取大厅中的一个房间
func (self * Hall) getRoom(roomID int) *Room {
	if v, ok := self.rooms[roomID]; ok {
		return v
	}
	return nil
}

